package com.szq.lottery.strategy.Impl;

import com.szq.lottery.DBContextHolder;
import com.szq.lottery.DBRouterConfig;
import com.szq.lottery.strategy.IDBRouterStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * @author 吾空白
 * @description: 哈希路由
 */
@Component
public class DBRouterStrategyHashCode implements IDBRouterStrategy  {

    private Logger logger= LoggerFactory.getLogger(DBRouterStrategyHashCode.class);

    private DBRouterConfig dbRouterConfig;

    public DBRouterStrategyHashCode(DBRouterConfig dbRouterConfig) {
        this.dbRouterConfig = dbRouterConfig;
    }

    //https://mp.weixin.qq.com/s/CySTVqEDK9-K1MRUwBKRCg
    @Override
    public void dbRouter(String dbKeyAttr) {
        int size=dbRouterConfig.getDbCount()*dbRouterConfig.getTbCount();
        // 扰动函数；在 JDK 的 HashMap 中，对于一个元素的存放，需要进行哈希散列。而为了让散列更加均匀，所以添加了扰动函数。扩展学习；https://mp.weixin.qq.com/s/CySTVqEDK9-K1MRUwBKRCg
        int idx=(size-1)&(dbKeyAttr.hashCode()^dbKeyAttr.hashCode()>>>16);

        //库表索引;相当于是把长条的桶，切割成段，对应分库分表中的库编号和表编号
        int dbIdx=idx/dbRouterConfig.getTbCount()+1;
        int tbIdx=idx-dbRouterConfig.getTbCount()*(dbIdx-1);

        //设置到ThreadLocal
        DBContextHolder.setDbKey(String.format("%02d",dbIdx));
        DBContextHolder.setTbKey(String.format("%03d",tbIdx));
        logger.info("数据库路由 dbIdx:{} tbIdx:{}",dbIdx,tbIdx);
    }

    @Override
    public void setDBKey(int dbIdx) {
        DBContextHolder.setTbKey(String.format("%02d",dbIdx));
    }

    @Override
    public void setTBKey(int tbIdx) {
        DBContextHolder.setTbKey(String.format("%03d",tbIdx));
    }

    @Override
    public int dbCount() {
        return dbRouterConfig.getDbCount();
    }

    @Override
    public int tbCount() {
        return dbRouterConfig.getTbCount();
    }

    @Override
    public void clear() {
        DBContextHolder.clearDBKey();
        DBContextHolder.clearTBKey();
    }
}
